package org.jetlinks.protocol.official.mqtt.up.zigbeeGateway;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetlinks.core.Value;
import org.jetlinks.core.device.DeviceOperator;
import org.jetlinks.core.message.DeviceMessage;
import org.jetlinks.core.message.codec.MqttMessage;
import org.jetlinks.core.message.function.FunctionInvokeMessageReply;
import org.jetlinks.core.message.property.ReportPropertyMessage;
import org.jetlinks.protocol.official.ObjectMappers;
import org.jetlinks.protocol.official.TopicPayload;
import org.jetlinks.protocol.official.mqtt.down.CacheKeyEnum;
import org.reactivestreams.Publisher;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @Author bingzhong
 * @Date 2024/12/30 18:07
 * @Description zigbee网关
 *
 */
@Slf4j
public class ZigbeeGatewayUpHandler {

    static ObjectMapper mapper = ObjectMappers.JSON_MAPPER;

    @SneakyThrows
    public static Publisher<DeviceMessage> doDecode(MqttMessage message, DeviceOperator deviceOperator) {

        TopicPayload topicPayload = TopicPayload.of(message.getTopic(), message.payloadAsBytes());

        JSONObject dataJson = mapper.readValue(topicPayload.getPayload(), JSONObject.class);

        String rfid = Optional.ofNullable(dataJson.get("rfid"))
                              .map(String::valueOf)
                              .orElse("");

        // 网关下发后回复消息
        if (StringUtils.hasLength(rfid)) {
            return fromReply2FunctionMessage(message, deviceOperator);
        }
        // 设备上报消息
        return fromReport2ReportPropertyMessage(dataJson);

    }

    private static Mono<DeviceMessage> fromReport2ReportPropertyMessage(JSONObject dataJson) {
        Map params = (Map) dataJson.get("param");
        String clientId = String.valueOf(params.get("id"));
        String name = String.valueOf(params.get("name"));
        List valueList = (List) params.get("value");
        JSONObject data = new JSONObject();
        data.put("deviceId", clientId);
        data.put(name, valueList.get(0));
        data.putAll(params);
        // 门锁电量格式化
        if ("BatteryPercentage".equalsIgnoreCase(name)) {
            int batteryPercentage = Integer.parseInt(String.valueOf(valueList.get(0)));
            data.put(name, batteryPercentage / 10.0);
        }
        ReportPropertyMessage reportPropertyMessage = new ReportPropertyMessage();
        reportPropertyMessage.setDeviceId(clientId);
        reportPropertyMessage.setProperties(data);
        return Mono.justOrEmpty(reportPropertyMessage);
    }

    @SneakyThrows
    public static Flux<DeviceMessage> fromReply2FunctionMessage(MqttMessage message, DeviceOperator deviceOperator) {
        log.error("收到网关回复消息:{}", message);
        String key = CacheKeyEnum.FunctionId_.name() + message.getClientId();
        JSONObject dataJson = mapper.readValue(message.payloadAsBytes(), JSONObject.class);
        return deviceOperator.getConfig(key)
                .defaultIfEmpty(Value.simple("empty"))
                .map(Value::asString)
                .flatMapMany(messageId -> {
                    FunctionInvokeMessageReply reply = new FunctionInvokeMessageReply();
                    reply.setMessageId(messageId);
                    reply.setDeviceId(message.getClientId());
                    reply.setOutput(dataJson);
                    Map params = (Map) dataJson.get("param");
                    if (params.get("name") != null) {
                        String name = String.valueOf(params.get("name"));
                        // 下发后更新插座状态信息
                        if ("Onoff".equals(name)) {
                            log.error("Onoff 执行");
                            List valueList = (List) params.get("value");
                            String clientId = String.valueOf(params.get("id"));
                            ReportPropertyMessage reportPropertyMessage = new ReportPropertyMessage();
                            reportPropertyMessage.setDeviceId(clientId);
                            reportPropertyMessage.setProperties(Collections.singletonMap("Onoff", valueList.get(0)));
                            return Flux.just(reply,reportPropertyMessage);
                        }
                    }
                    return Flux.just(reply);
                });

    }


}
